﻿using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;
using System.ComponentModel;
using Windows.Devices.Geolocation;
using Yuanna.Model;
using System.Threading;
using System.Windows.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
using Yuanna.Resources;

namespace Yuanna
{
    public partial class MainPage : PhoneApplicationPage
    {
        ProgressIndicator _prog;

        DispatcherTimer _timer;
        DateTime _startTime;
        TimeSpan _durationTime = new TimeSpan(0);
        TimeSpan _pauseTime = new TimeSpan(0);
        Point _beforePoint;
        double _distance;
        double _speed;

        YuannaPath _currentYuannaPath;
        Geolocator _geo;
        bool _isTracking = false;
        int _pauseCount = 0;

        string _appTitle = AppResources.ApplicationTitle;
        string _statusUnstartOrStopedText = AppResources.StatusUnstartOrStoped;
        string _statusPausedText = AppResources.StatusPaused;
        string _statusDisabled = AppResources.StatusDisabled;
        string _statusInitializing = AppResources.StatusInitializing;
        string _statusNoData = AppResources.StatusNoData;
        string _statusReady = AppResources.StatusReady;
        string _statusNotAvailable = AppResources.StatusNotAvailable;
        string _statusText;

        Color _statusUnstartOrStopedColor = Colors.Brown;
        Color _statusTrackingColor = Colors.Green;
        Color _statusPauseColor = Colors.Purple;
        Color _statusColor;

        // 构造函数
        public MainPage()
        {
            InitializeComponent();

            SystemTray.SetIsVisible(this, true);
            SystemTray.SetBackgroundColor(this, _statusUnstartOrStopedColor);
            SystemTray.SetForegroundColor(this, Colors.White);

            _prog = new ProgressIndicator();
            _prog.IsVisible = true;
            _prog.IsIndeterminate = false;
            _prog.Text = string.Concat(_appTitle, " - ", _statusUnstartOrStopedText);
            SystemTray.SetProgressIndicator(this, _prog);

            DataContext = App.ViewModel;
        }

        /// <summary>
        /// 进入此页面
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (!App.ViewModel.IsDataLoaded)
            {
                App.ViewModel.LoadDataFromDb();
            }
        }
        
        /// <summary>
        /// 离开此页面
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            App.ViewModel.SaveChangesToDb();
        }

        private void startTrackingAppBarButton_Click(object sender, EventArgs e)
        {
            if (_pauseCount == 0) // 首次开始
            {
                if (_isTracking == false)
                {
                    _geo = new Geolocator(); // 地理位置访问服务
                    _geo.DesiredAccuracy = PositionAccuracy.High; // 精度级别
                    _geo.MovementThreshold = 5; // 超过多少米引发位置改变事件
                    _geo.StatusChanged += geolocator_StatusChanged; // 功能状态改变时
                    _geo.PositionChanged += geolocator_PositionChanged; // 位置改变时

                    _isTracking = true;

                    // 先在数据表中添加一个路径，然后让坐标点逐时写入
                    _currentYuannaPath = new YuannaPath { IsTracking = true, CreateTime = DateTime.Now, IsSync = false, IsDelete = false };
                    App.ViewModel.AddPathToDb(_currentYuannaPath);
                    App.ViewModel.LoadDataFromDb();

                    if (App.ViewModel.AllPaths.Count > 0)
                    {
                        listBoxAllPaths.ScrollTo(listBoxAllPaths.ItemsSource[0]);
                    }

                    _beforePoint = new Point(0, 0);
                    _startTime = DateTime.Now;

                    // 计时器
                    _timer = new DispatcherTimer();
                    _timer.Interval = new TimeSpan(10000000);//定时器间隔为1秒
                    _timer.Tick += timer_Tick;
                    _timer.Start();

                    Dispatcher.BeginInvoke(() =>
                    {
                        var buttons = this.ApplicationBar.Buttons;
                        ((ApplicationBarIconButton)buttons[0]).IsEnabled = false;
                        ((ApplicationBarIconButton)buttons[1]).IsEnabled = true;
                        ((ApplicationBarIconButton)buttons[2]).IsEnabled = true;
                    });
                }
            }
            else // 由暂停恢复到开始
            {
                if (_timer != null && _geo != null)
                {
                    _pauseTime = DateTime.Now - DateTime.MinValue - _pauseTime; // 获取暂停时间
                    _startTime += _pauseTime; // 重置开始时间
                    _geo.PositionChanged += geolocator_PositionChanged;
                    _geo.StatusChanged += geolocator_StatusChanged;
                    _timer.Start();

                    Dispatcher.BeginInvoke(() =>
                    {
                        ShowStatusBarByGeoStatus(_geo.LocationStatus);

                        var buttons = this.ApplicationBar.Buttons;
                        ((ApplicationBarIconButton)buttons[0]).IsEnabled = false;
                        ((ApplicationBarIconButton)buttons[1]).IsEnabled = true;
                        ((ApplicationBarIconButton)buttons[2]).IsEnabled = true;
                    });
                }
            }
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            _durationTime = DateTime.Now - _startTime;
            _currentYuannaPath.Duration = new TimeSpan(_durationTime.Hours, _durationTime.Minutes, _durationTime.Seconds).ToString();
            _currentYuannaPath.Distance = _distance;
            _currentYuannaPath.Speed = _speed;
        }

        private void pauseTrackingAppBarButton_Click(object sender, EventArgs e)
        {
            _pauseCount = 1;
            _pauseTime = DateTime.Now - DateTime.MinValue; // 获取暂停时间起始点
            if (_geo != null)
            {
                _geo.PositionChanged -= geolocator_PositionChanged;
                _geo.StatusChanged -= geolocator_StatusChanged;
            }

            if (_timer != null)
            {
                _timer.Stop();
            }

            Dispatcher.BeginInvoke(() =>
            {
                _statusColor = _statusPauseColor;
                _statusText = _statusPausedText;

                SystemTray.SetBackgroundColor(this, _statusColor);
                _prog.Text = string.Concat(_appTitle, " - ", _statusText);

                var buttons = this.ApplicationBar.Buttons;
                ((ApplicationBarIconButton)buttons[0]).IsEnabled = true;
                ((ApplicationBarIconButton)buttons[1]).IsEnabled = false;
                ((ApplicationBarIconButton)buttons[2]).IsEnabled = true;
            });
        }

        private void stopTrackingAppBarButton_Click(object sender, EventArgs e)
        {
            if (_timer != null)
            {
                _timer.Stop();
                _timer = null;
            }

            if (_geo != null)
            {
                _geo.PositionChanged -= geolocator_PositionChanged;
                _geo.StatusChanged -= geolocator_StatusChanged;
                _geo = null;
            }
            
            _isTracking = false;
            _currentYuannaPath.IsTracking = _isTracking;
            _currentYuannaPath.GetAverageSpeed();
            App.ViewModel.SaveChangesToDb();
            App.ViewModel.LoadDataFromDb();

            _currentYuannaPath = null;
            _durationTime = new TimeSpan(0);
            _pauseTime = new TimeSpan(0);
            _beforePoint = new Point(0, 0);
            _distance = 0;
            _speed = 0;
            _pauseCount = 0;

            Dispatcher.BeginInvoke(() =>
            {
                _statusColor = _statusUnstartOrStopedColor;
                _statusText = _statusUnstartOrStopedText;

                SystemTray.SetBackgroundColor(this, _statusColor);
                _prog.Text = string.Concat(_appTitle, " - ", _statusText);

                var buttons = this.ApplicationBar.Buttons;
                ((ApplicationBarIconButton)buttons[0]).IsEnabled = true;
                ((ApplicationBarIconButton)buttons[1]).IsEnabled = false;
                ((ApplicationBarIconButton)buttons[2]).IsEnabled = false;
            });
        }

        void geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
        {
            ShowStatusBarByGeoStatus(args.Status);
        }

        void ShowStatusBarByGeoStatus(PositionStatus argPositionStatus)
        {
            switch (argPositionStatus)
            {
                case PositionStatus.Disabled:
                    _statusColor = _statusUnstartOrStopedColor;
                    _statusText = _statusDisabled;
                    break;
                case PositionStatus.Initializing:
                    _statusColor = _statusTrackingColor;
                    _statusText = _statusInitializing;
                    break;
                case PositionStatus.NoData:
                    _statusColor = _statusUnstartOrStopedColor;
                    _statusText = _statusNoData;
                    break;
                case PositionStatus.Ready:
                    _statusColor = _statusTrackingColor;
                    _statusText = _statusReady;
                    break;
                case PositionStatus.NotAvailable:
                case PositionStatus.NotInitialized:
                    _statusColor = _statusUnstartOrStopedColor;
                    _statusText = _statusNotAvailable;
                    break;
            }

            Dispatcher.BeginInvoke(() =>
            {
                SystemTray.SetBackgroundColor(this, _statusColor);
                _prog.Text = string.Concat(_appTitle, " - ", _statusText);
            });
        }

        void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
        {
            if (_geo.LocationStatus == PositionStatus.Ready && _currentYuannaPath != null && args.Position.Coordinate.Speed != null)
            {
                if (args.Position.Coordinate.Speed.Equals(double.NaN) == false)
                {
                    // 速度，换算成千米每小时
                    _speed = (double)args.Position.Coordinate.Speed * 3.6;
                }

                // 距离
                var currentPoint = new Point(args.Position.Coordinate.Longitude, args.Position.Coordinate.Latitude);
                if (_beforePoint != new Point(0, 0))
                {
                    _distance += GetDistance(currentPoint.Y, currentPoint.X, _beforePoint.Y, _beforePoint.X);
                }

                // 坐标点
                var point = new YuannaPoint
                {
                    Path = _currentYuannaPath,
                    CreateTime = DateTime.Now,
                    Latitude = args.Position.Coordinate.Latitude,
                    Longitude = args.Position.Coordinate.Longitude,
                    Speed = _speed
                };

                // 添加当前坐标点
                App.ViewModel.AddYuannaPoint(point);

                _beforePoint = currentPoint;
            }
        }

        private static double rad(double d)
        {
            return d * Math.PI / 180.0;
        }

        public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
        {
            double EARTH_RADIUS = 6378.137;
            double radLat1 = rad(lat1);
            double radLat2 = rad(lat2);
            double a = radLat1 - radLat2;
            double b = rad(lng1) - rad(lng2);
            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
            Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * EARTH_RADIUS;
            s = Math.Round(s * 10000) / 10000;
            return s;
        }

        private void yuannaPathItem_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            var yuannaPath = (sender as FrameworkElement).DataContext as YuannaPath;
            if (yuannaPath != null)
            {
                NavigationService.Navigate(new Uri("/YuannaPathMap.xaml?pa_id=" + yuannaPath.Id, UriKind.Relative));
            }
        }

        /// <summary>
        /// 为每个列表项绑定上下文菜单
        /// 由于采用前台方式(嵌入XAML代码)会导致 上下文菜单 所绑定的数据源项 变得不确定
        /// 所以采用后台代码的方式为 菜单项动态绑定
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void yuannaPathItem_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            var wrap = sender as Grid;

            MenuItem menuItem1 = new MenuItem();
            menuItem1.Header = "删除";
            menuItem1.Click += new RoutedEventHandler(deleteYuannaPath_Click);

            MenuItem menuItem2 = new MenuItem();
            menuItem2.Header = "查看详情";
            menuItem2.Click += new RoutedEventHandler(showYuannaPathPoints_Click);

            ContextMenu menu = new ContextMenu();
            menu.IsZoomEnabled = false;
            menu.Items.Add(menuItem1);
            menu.Items.Add(menuItem2);

            ContextMenuService.SetContextMenu(wrap, menu);
        }

        private void deleteYuannaPath_Click(object sender, RoutedEventArgs e)
        {
            YuannaPath yuannaPath = (sender as MenuItem).DataContext as YuannaPath;
            // 不允许删除正在追踪中的项
            if (yuannaPath != null && yuannaPath.IsTracking == false)
            {
                App.ViewModel.DeletePath(yuannaPath);
            }
        }

        private void showYuannaPathPoints_Click(object sender, RoutedEventArgs e)
        {
            var yuannaPath = (sender as MenuItem).DataContext as YuannaPath;
            if (yuannaPath != null)
            {
                //MessageBox.Show(yuannaPath.Id.ToString(), "path_id", MessageBoxButton.OKCancel);
                NavigationService.Navigate(new Uri("/YuannaPathPoint.xaml?path_id=" + yuannaPath.Id, UriKind.Relative));
            }
        }
    }
}